package org.fireking.myapplication.drawing.impl

import android.graphics.Canvas
import android.graphics.Paint
import android.graphics.Path
import android.util.Log
import com.github.mikephil.charting.utils.Transformer
import org.fireking.myapplication.ChartDrawingRenderer
import org.fireking.myapplication.drawing.ShapeDrawingStrategy

class CurveDrawingStrategy(val points: MutableList<Pair<Float, Float>>) : ShapeDrawingStrategy {
    override fun draw(canvas: Canvas, transformer: Transformer?, paint: Paint) {
        transformer ?: return
        val path = Path()
        if (points.isEmpty()) return
        val first = points.first()
        val firstPoints = floatArrayOf(first.first, first.second)
        transformer.pointValuesToPixel(firstPoints)
        path.moveTo(firstPoints[0], firstPoints[1])
        for (i in 1 until points.size) {
            val point = points[i]
            val pointsArray = floatArrayOf(point.first, point.second)
            transformer.pointValuesToPixel(pointsArray)
            path.lineTo(pointsArray[0], pointsArray[1])
        }
        canvas.drawPath(path, paint)
    }
    override fun containsPoint(x: Float, y: Float, touchTolerance: Float): Boolean {
        if (points.size < 2) return false
        for (i in 0 until points.size - 1) {
            val p1 = points[i]
            val p2 = points[i + 1]
            if (isPointNearLine(
                    x, y, p1.first, p1.second, p2.first, p2.second, touchTolerance
                )
            ) {
                return true
            }
        }
        return false
    }
    private fun isPointNearLine(
        px: Float, py: Float, x1: Float, y1: Float, x2: Float, y2: Float, tolerance: Float
    ): Boolean {
        val a = px - x1
        val b = py - y1
        val c = x2 - x1
        val d = y2 - y1
        val dot = a * c + b * d
        val lenSq = c * c + d * d
        var param = -1f
        if (lenSq != 0f) param = dot / lenSq
        var xx: Float
        var yy: Float
        if (param < 0f) {
            xx = x1
            yy = y1
        } else if (param > 1f) {
            xx = x2
            yy = y2
        } else {
            xx = x1 + param * c
            yy = y1 + param * d
        }
        val dx = px - xx
        val dy = py - yy
        val distance = Math.sqrt((dx * dx + dy * dy).toDouble()).toFloat()
        return distance <= tolerance
    }
    override fun containsPointInside(x: Float, y: Float, edgeTolerance: Float): Boolean {
        if (points.size < 3) {
            Log.d("CurveDrawingStrategy", "Not enough points for inside check")
            return false
        }
        val middleIndex = points.size / 2
        val rangeStart = Math.max(1, middleIndex - points.size / 4)
        val rangeEnd = Math.min(points.size - 1, middleIndex + points.size / 4)
        Log.d(
            "CurveDrawingStrategy",
            "Checking middle segments: range=$rangeStart-$rangeEnd of ${points.size} points"
        )
        for (i in rangeStart until rangeEnd) {
            val p1 = points[i]
            val p2 = points[i + 1]
            if (isPointNearLineSegment(
                    x, y, p1.first, p1.second, p2.first, p2.second, edgeTolerance
                )
            ) {
                Log.d("CurveDrawingStrategy", "Found point near middle segment: i=$i")
                return true
            }
        }
        return false
    }
    private fun isPointNearLineSegment(
        px: Float, py: Float, x1: Float, y1: Float, x2: Float, y2: Float, tolerance: Float
    ): Boolean {
        val a = px - x1
        val b = py - y1
        val c = x2 - x1
        val d = y2 - y1
        val dot = a * c + b * d
        val lenSq = c * c + d * d
        if (lenSq == 0f) return false
        var param = dot / lenSq
        if (param < 0f || param > 1f) return false
        val xx = x1 + param * c
        val yy = y1 + param * d
        val dx = px - xx
        val dy = py - yy
        val distance = Math.sqrt((dx * dx + dy * dy).toDouble()).toFloat()
        return distance <= tolerance
    }
    override fun getControlPoints(): List<ChartDrawingRenderer.ControlPoint> {
        return points.mapIndexed { index, point ->
            ChartDrawingRenderer.ControlPoint(
                index,
                point.first,
                point.second,
                ChartDrawingRenderer.ControlPointType.CORNER
            )
        }
    }
    override fun applyControlPointMove(controlPointId: Int, deltaX: Float, deltaY: Float) {
        if (controlPointId >= 0 && controlPointId < points.size) {
            val point = points[controlPointId]
            points[controlPointId] = Pair(point.first + deltaX, point.second + deltaY)
        }
    }
    override fun move(deltaX: Float, deltaY: Float) {
        for (i in points.indices) {
            val point = points[i]
            points[i] = Pair(point.first + deltaX, point.second + deltaY)
        }
    }
}